//----------------------------------------------------------------------------// // // // R u n s T a b l e F a c t o r y // // // //----------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. // // This software is released under the GNU General Public License. // // Goto http://kenai.com/projects/audiveris to report bugs or suggestions. // //----------------------------------------------------------------------------// // </editor-fold> package omr.run; import net.jcip.annotations.NotThreadSafe; import net.jcip.annotations.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.Dimension; import java.awt.Rectangle; /** * Class {@code RunsTableFactory} retrieves the runs structure out of * a given pixel source and builds the related {@link RunsTable} * structure. * * @author Hervé Bitteur */ public class RunsTableFactory { //~ Static fields/initializers --------------------------------------------- /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger( RunsTableFactory.class); //~ Instance fields -------------------------------------------------------- // /** The source to read runs of pixels from */ private final PixelFilter source; /** The desired orientation */ private final Orientation orientation; /** The minimum value for a run length to be considered */ private final int minLength; /** Remember if we have to swap x and y coordinates */ private final boolean swapNeeded; /** The created RunsTable */ private RunsTable table; //~ Constructors ----------------------------------------------------------- // // ------------------// // RunsTableFactory // // ------------------// /** * Create an RunsTableFactory, with its key parameters. * * @param orientation the desired orientation of runs * @param source the source to read runs from. * Orientation parameter is used to properly access the * source pixels. * @param minLength the minimum length for each run */ public RunsTableFactory (Orientation orientation, PixelFilter source, int minLength) { this.orientation = orientation; this.source = source; this.minLength = minLength; swapNeeded = orientation.isVertical(); } //~ Methods ---------------------------------------------------------------- // // ------------// // createTable // // ------------// /** * Report the RunsTable created with the runs retrieved from the * provided source. * * @param name the name to be assigned to the table * @return a populated RunsTable */ public RunsTable createTable (String name) { table = new RunsTable( name, orientation, new Dimension(source.getWidth(), source.getHeight())); RunsRetriever retriever = new RunsRetriever( orientation, new MyAdapter()); retriever.retrieveRuns( new Rectangle(0, 0, source.getWidth(), source.getHeight())); return table; } //~ Inner Classes ---------------------------------------------------------- // // -----------// // MyAdapter // // -----------// private class MyAdapter implements RunsRetriever.Adapter { //~ Methods ------------------------------------------------------------ // --------// // backRun // // --------// @Override public final void backRun (int coord, int pos, int length) { // No interest in background runs } // --------// // foreRun // // --------// @Override public final void foreRun (int coord, int pos, int length, int cumul) { // We consider only runs that are longer than minLength if (length >= minLength) { final int level = ((2 * cumul) + length) / (2 * length); // if (pos > 730 && pos < 737) // logger.info( "pos\t{}\t{}\t{}\t{}\t{}", // pos, coord, length, cumul, level); // if (coord > 157 && coord < 164 ) // logger.info( "coord\t{}\t{}\t{}\t{}\t{}", // pos, coord, length, cumul, level); table.getSequence(pos) .add(new Run(coord - length, length, level)); } } // ---------// // getLevel // // ---------// @Override public final int getLevel (int coord, int pos) { if (swapNeeded) { return source.getPixel(pos, coord); } else { return source.getPixel(coord, pos); } } // -------// // isFore // // -------// @Override public final boolean isFore (int coord, int pos) { if (swapNeeded) { return source.isFore(pos, coord); } else { return source.isFore(coord, pos); } } // ----------// // terminate // // ----------// @Override public final void terminate () { logger.debug("{} Retrieved runs: {}", table, table.getRunCount()); } //--------------// // isThreadSafe // //--------------// /** * The concurrency aspects of the adapter depends on the * underlying PixelFilter. * * @return true if safe, false otherwise */ @Override public boolean isThreadSafe () { Class<?> classe = source.getClass(); // Check for @ThreadSafe annotation ThreadSafe safe = classe.getAnnotation(ThreadSafe.class); if (safe != null) { return true; } // Check for @NonThreadSafe annotation NotThreadSafe notSafe = classe.getAnnotation(NotThreadSafe.class); if (notSafe != null) { return false; } // No annotation: it's safer to assume no thread safety return false; } } }